package org.chen.admin.web.controller.common;

import com.google.code.kaptcha.Producer;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.config.ChenConfig;
import org.chen.admin.web.controller.common.utils.uuid.IdUtils;
import org.chen.common.constant.CacheConstants;
import org.chen.common.core.domain.AjaxResult;
import org.chen.common.dto.CaptchaResponse;
import org.chen.common.redis.RedisCache;
import org.chen.common.utils.sign.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@RestController
@Tag(name = "验证码")
@Slf4j
public class CaptchaController {

    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ChenConfig chenConfig;

    @GetMapping("/captchaImage")
    @Operation(summary = "获取图形验证码", description = "返回验证码图片的base64编码和UUID")
    @ApiResponses({
        @ApiResponse(
            responseCode = "200",
            description = "查询成功",
            content = @Content(
                mediaType = "application/json",
                schema = @Schema(implementation = CaptchaResponse.class)
            )
        )
    })
    public AjaxResult getCode() {
        AjaxResult result = AjaxResult.success();
//        log.info("登录验证码");
//        获取验证码信息
//      获取一个随机的uuid
        String uuid = IdUtils.simpleUUID();

        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;

        String capStr = null, code = null;
        BufferedImage image = null;

        String captchaType = chenConfig.getCaptchaType();
        // 这段代码用于根据配置生成不同类型的验证码图片和内容。
        // captchaType 可以是 "math" 或 "char" 两种类型：
        // - 如果是 "math"，会生成一个带有算术表达式的验证码，比如 "1+2@3"，"@"前的是图片显示内容，"@"后的是答案。
        //   capStr 取表达式部分，code 取答案，image 用 capStr 生成。
        // - 如果是 "char"，则生成普通字符验证码，文本即为图片内容，也是验证答案。
        // captchaType的值通过调用RuoYiConfig.getCaptchaType()方法获得，
        // 该方法一般会从配置文件或全局配置中读取当前系统设置的验证码类型。
        // 如果配置在运行时发生了变化，或者配置的读取不是线程安全或全局唯一的，
        // 那么在并发或多次请求时，captchaType值可能会出现不一样的情况。
        // 例如，一个请求时配置为"math"，而另一个请求时配置修改为"char"，则两次请求取值不同。
        // captchaType 的值来源于 RuoYiConfig.getCaptchaType() 方法。
        // 具体来讲，RuoYiConfig 通常是一个全局配置类，其 getCaptchaType() 方法会读取应用的验证码类型设定。
        // 这个配置可能来源于配置文件（如 application.yml）、数据库或者其他配置中心。
        // 一般来说，系统启动时会把配置加载进静态变量，getCaptchaType() 返回该静态变量的值。
        // 例如，当在配置文件中配置了 ruoyi.captchaType=math，则 getCaptchaType() 返回 "math"。
        // 因此，captchaType 的值是通过全局配置统一控制的。
        if ("math".equals(captchaType)) {
//         如果是 "math"，会生成一个带有算术表达式的验证码，比如 "1+2@3"，"@"前的是图片显示内容，"@"后的是答案
            String capText = captchaProducerMath.createText();//3*5=?@15
            capStr = capText.substring(0, capText.lastIndexOf("@"));//3*5=?
            code = capText.substring(capText.lastIndexOf("@") + 1);//15
            image = captchaProducerMath.createImage(capStr);
        } else if ("char".equals(captchaType)) {
//            如果是 "char"，则生成普通字符验证码，文本即为图片内容，也是验证答案
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }

//        存入redis中，便于在登录时进行验证
        redisCache.setCacheObject(verifyKey, code, CacheConstants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);

        FastByteArrayOutputStream os = new FastByteArrayOutputStream();

        try {
            ImageIO.write(image, "jpg", os);
        } catch (IOException e) {
//            throw new RuntimeException(e);
            return AjaxResult.error(e.getMessage());
        }
        result.put("uuid", uuid);
        result.put("img", Base64.encode(os.toByteArray()));
        return result;

    }
}
